package com.example.axon;


import com.example.axon.commands.*;
import com.example.axon.events.*;
import com.example.axon.utils.JsonMapper;
import com.example.axon.utils.Protostuff;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.axonframework.commandhandling.CommandHandler;
import org.axonframework.eventsourcing.EventSourcingHandler;
import org.axonframework.modelling.command.AggregateIdentifier;
import org.axonframework.spring.stereotype.Aggregate;

import static org.axonframework.modelling.command.AggregateLifecycle.apply;

@Slf4j
@Aggregate(snapshotTriggerDefinition = "accountAggregateTrigger")
@NoArgsConstructor
public class AccountAggregate {

    @AggregateIdentifier
    private String id;
    private String userName;
    private String password;
    private String email;
    private Double balance;

    @CommandHandler
    public AccountAggregate(CreateCmd cmd) {

        log.info("createCmd: {}",cmd);

        apply(JsonMapper.getInstance().convertValue(cmd, CreateEvent.class));
    }

    @CommandHandler
    public void onAdd(AddCmd cmd) {
        log.info("AddCmd: {}",cmd);

        AddEvent payload = JsonMapper.getInstance().convertValue(cmd, AddEvent.class);
        apply(payload);
    }

    @CommandHandler
    public void onSubtract(SubtractCmd cmd) {
        log.info("SubtractCmd: {}",cmd);

        apply(JsonMapper.getInstance().convertValue(cmd, CreateEvent.class));
    }


    @CommandHandler
    public void transferIn(TransferInCmd cmd) {
        log.info("TransferInCmd: {}",cmd);

        apply(JsonMapper.getInstance().convertValue(cmd, AddEvent.class))
                .andThenApply(() -> JsonMapper.getInstance().convertValue(cmd, TransferFinishEvent.class));
    }

    @CommandHandler
    public void transferOut(TransferOutCmd cmd) {
        log.info("TransferOutCmd: {}",cmd);

//        throw new RuntimeException("hello test handler");
//
        SubtractEvent build = Protostuff.lombokBuilder(cmd, SubtractEvent.SubtractEventBuilder.class).build();
        apply(build).andThenApply(() ->
                Protostuff.lombokBuilder(cmd, TransferOutEvent.TransferOutEventBuilder.class)
                        .accountId(cmd.getFromId())
                        .build()
        );
    }


    @EventSourcingHandler
    public void create(CreateEvent cmd) {
        id = cmd.getAccountId();
        userName = cmd.getUserName();
        password = cmd.getPassword();
        balance = cmd.getBalance();
    }

    @EventSourcingHandler
    public void add(AddEvent cmd) {
        balance += cmd.getBalance();

    }

    @EventSourcingHandler
    public void subtract(SubtractEvent cmd) {
        balance -= cmd.getBalance();

    }


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Double getBalance() {
        return balance;
    }

    public void setBalance(Double balance) {
        this.balance = balance;
    }
}
